﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Windows.Forms;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using OpenComposite.Workflow.Properties;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Workflow.ComponentModel.Compiler;
using OpenComposite.Workflow.Interfaces;

namespace OpenComposite.Workflow
{
	[ActivityValidator(typeof(DecisionActivityValidator))]
	public class DecisionActivity : CompositeActivity
	{
		HorizontalWorkflowActivity _root;

		protected HorizontalWorkflowActivity Root
		{
			get
			{
				if ( _root == null ) {
					_root = GetRoot(this) as HorizontalWorkflowActivity;
				}
				return _root;
			}
		}

		private CompositeActivity GetRoot(Activity current)
		{
			CompositeActivity temp = new CompositeActivity();
			if ( current.Parent == null )
				return current as CompositeActivity;
			else
				return GetRoot(current.Parent);
		}

		protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
		{
			// implement random execute
			if ( EnabledActivities.Count == 0 )
				return ActivityExecutionStatus.Closed;

			Random rnd = new Random();

			double sum = 0;
			double chance = rnd.NextDouble() * 100;

			IList<Activity> branches = new List<Activity>(EnabledActivities);

			branches = WorkflowHelpers.ShuffleList(branches);

			foreach ( HorizontalSequenceActivity branch in branches ) {
				if ( branch.AnalyticChance == 0 )
					continue;
				if ( chance > sum && chance <= sum + branch.AnalyticChance ) {
					branch.Closed += continueAt;
					executionContext.ExecuteActivity(branch);
					break;
				}
				sum += branch.AnalyticChance;
			}
			return ActivityExecutionStatus.Executing;
		}

		void continueAt(object sender, ActivityExecutionStatusChangedEventArgs e)
		{
			e.Activity.Closed -= this.continueAt;
			ActivityExecutionContext context = sender as ActivityExecutionContext;
			WorkflowHelpers.CompleteCloseContext(context);
			bool okToClose = true;
			foreach ( Activity activity in ( (CompositeActivity)context.Activity ).EnabledActivities ) {
				if ( activity.ExecutionStatus != ActivityExecutionStatus.Closed &&
					 activity.ExecutionStatus != ActivityExecutionStatus.Initialized ) {
					activity.Closed += continueAt;
					context.CancelActivity(activity);
					okToClose = false;
				}
			}
			if ( okToClose ) {
				if ( context.Activity.ExecutionStatus == ActivityExecutionStatus.Faulting &&
					 context.ExecutionContextManager.ExecutionContexts.Count == 0 ) {
					context.CloseActivity();
				} else {
				}
			}
		}

		protected override ActivityExecutionStatus HandleFault(ActivityExecutionContext executionContext, Exception exception)
		{
			Activity faultHandler = WorkflowHelpers.GetAlternateFlowActivity(Activities, typeof(HorizontalFaultHandlersActivity));
			if ( faultHandler != null ) {
				if ( faultHandler.ExecutionStatus == ActivityExecutionStatus.Initialized ) {
					faultHandler.Closed += continueAt;
					executionContext.ExecuteActivity(faultHandler);
				} else {
					ExecuteInNewContext(executionContext, faultHandler);
				}
			}
			return base.HandleFault(executionContext, exception);
		}

		protected override ActivityExecutionStatus Cancel(ActivityExecutionContext executionContext)
		{
			Activity cancellationHandler = WorkflowHelpers.GetAlternateFlowActivity(Activities, typeof(HorizontalCancellationHandlerActivity));
			if ( cancellationHandler != null ) {
				if ( cancellationHandler.ExecutionStatus == ActivityExecutionStatus.Initialized ) {
					cancellationHandler.Closed += continueAt;
					executionContext.ExecuteActivity(cancellationHandler);
				} else {
					ExecuteInNewContext(executionContext, cancellationHandler);
				}
			}
			if ( executionContext.Activity.ExecutionStatus == ActivityExecutionStatus.Faulting )
				return ActivityExecutionStatus.Faulting;

			return base.Cancel(executionContext);
		}

		private void ExecuteInNewContext(ActivityExecutionContext context, Activity target)
		{
			ExecuteInNewContext(context, target, true);
		}

		private void ExecuteInNewContext(ActivityExecutionContext context, Activity target, bool continueExecution)
		{
			ActivityExecutionContext newContext = context.ExecutionContextManager.CreateExecutionContext(target);
			if ( continueExecution ) {
				newContext.Activity.Closed += continueAt;
			}
			try {
				newContext.ExecuteActivity(newContext.Activity);
			} catch ( Exception ex ) {
				EventLog.WriteEntry("HorizontalSequence.cs", ex.ToString());
			}
		}

		public new ReadOnlyCollection<Activity> EnabledActivities
		{
			get
			{
				List<Activity> list = new List<Activity>();
				foreach ( Activity activity in base.EnabledActivities ) {
					if ( activity.Enabled && !WorkflowHelpers.IsFrameworkActivity(activity) ) {
						list.Add(activity);
					}
				}
				return list.AsReadOnly();
			}
		}
	}

	public class DecisionDesigner : SequentialActivityDesigner
	{
		/// <summary>
		/// Indicates the height and width of the split and join symbols
		/// </summary>
		protected const int width = 40;
		/// <summary>
		/// Used for drawing split and join symbols
		/// </summary>
		protected Rectangle bounds; //used for paint split/join
		private const int height = 40;
		private const int joinSize = 16;
		private ActivityDesignerVerbCollection verbs = null;
		private Rectangle _ExpandButtonRectangle = new Rectangle(0, 0, 8, 8);
		//private Rectangle _collapsedEllipsis = new Rectangle();
		private List<Activity> _branchList = new List<Activity>();
		protected Pen outerSymbolPen = new Pen(Brushes.DarkGreen, 1.5F);
		private Font _bigFont = new Font(FontFamily.GenericSansSerif, 16.0F, FontStyle.Bold);
		private Font _mediumFont = new Font(FontFamily.GenericSansSerif, 10.0F, FontStyle.Regular);
		private List<DesignerView> _views = null;
		private LinearGradientBrush _backBrush = null;

		protected virtual LinearGradientBrush BackgroundBrush
		{
			get
			{
				//if ( _backBrush == null ) {
				Point start = new Point(bounds.Top + Bounds.Height / 2, bounds.Top);
				Point end = new Point(bounds.Top + Bounds.Height / 2, bounds.Bottom);
				_backBrush = new LinearGradientBrush(start, end, Color.White, Color.Green);
				//}
				return _backBrush;
			}
		}
		protected virtual Pen ConnectorPen
		{
			get { return new Pen(Color.Black); }
		}
		protected virtual SolidBrush JoinBrush
		{
			get { return (SolidBrush)Brushes.Black; }
		}

		List<Point> splitPoints;
		List<Point> joinPoints;
		List<Point> innerPoints;

		protected override void OnPaint(ActivityDesignerPaintEventArgs e)
		{
			if ( !this.IsVisible )
				return;

			if ( Expanded ) {
				#region Draw when expanded
				PaintContainedDesigners(e);

				bounds = new Rectangle(Bounds.X, Bounds.Y + ( Bounds.Height / 2 ) - ( height / 2 ), width, height);

				if ( this == ActiveView.AssociatedDesigner ) {
					// draw start diamond
					if ( e.Graphics.IsVisible(bounds) )
						PaintSplit(e);

					// change position to end

					bounds.X += Bounds.Width - width;

					// draw end diamond
					if ( e.Graphics.IsVisible(bounds) )
						PaintJoin(e);
				}
				splitPoints = new List<Point>(GetSplitConnections());
				joinPoints = new List<Point>(GetJoinConnections());
				innerPoints = new List<Point>(GetInnerConnections(DesignerEdges.Left));

				// draw split connectors
				for ( int i = 0; i < innerPoints.Count; i++ ) {
					if ( e.Graphics.IsVisible(GetSplitRectangle()) ) {
						if ( innerPoints[i].Y < splitPoints[0].Y )
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { splitPoints[0], new Point(splitPoints[0].X, innerPoints[i].Y), innerPoints[i] },
								LineAnchor.None, LineAnchor.None);
						else if ( innerPoints[i].Y == splitPoints[1].Y )
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { splitPoints[1], innerPoints[i] },
								LineAnchor.None, LineAnchor.None);
						else if ( innerPoints[i].Y > splitPoints[2].Y )
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { splitPoints[2], new Point(splitPoints[2].X, innerPoints[i].Y), innerPoints[i] },
								LineAnchor.None, LineAnchor.None);
						else
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { splitPoints[1], 
                                new Point(innerPoints[i].X - ((innerPoints[i].X - splitPoints[1].X) / 2), splitPoints[1].Y), 
                                new Point(innerPoints[i].X - ((innerPoints[i].X - splitPoints[1].X) / 2),innerPoints[i].Y), 
                                innerPoints[i] },
								LineAnchor.None, LineAnchor.None);
					}
				}

				innerPoints = new List<Point>(GetInnerConnections(DesignerEdges.Right));

				//draw join connectors 
				string branchText = "";
				for ( int i = 0; i < innerPoints.Count; i++ ) {
					//also handle branch names here
					if ( this is EventBasedXOrDesigner ) {
						if ( ( (CompositeActivity)this.ContainedDesigners[i].Activity ).Activities.Count > 0 ) {
							IncomingEvent evt = ( (CompositeActivity)this.ContainedDesigners[i].Activity ).Activities[0] as IncomingEvent;
							if ( evt != null ) {
								//if ( evt.EventType != EventType.Termination ) {
								e.Graphics.FillEllipse(e.DesignerTheme.ForegroundBrush,
									new Rectangle(innerPoints[i].X, innerPoints[i].Y - 5, 10, 10));
								if ( evt.EventType == EventType.None ) continue;

								if ( !string.IsNullOrEmpty(evt.Text) ) branchText = evt.Text;
								else if ( !string.IsNullOrEmpty(evt.EventName) ) branchText = evt.EventName;
								else continue;


								e.Graphics.DrawString(branchText,
									e.DesignerTheme.Font,
									e.DesignerTheme.ForegroundBrush,
									new RectangleF(
										new PointF(Bounds.X + width / 2 + 12, WorkflowHelpers.GetCenter(ContainedDesigners[i].Bounds).Y - 29),
										new SizeF(90, 19)));

								continue;
								//}
							}
						}
					}
					if ( e.Graphics.IsVisible(GetJoinRectangle()) ) {
						if ( innerPoints[i].Y < joinPoints[0].Y )
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { innerPoints[i], new Point(joinPoints[0].X, innerPoints[i].Y), joinPoints[0] },
								LineAnchor.None, LineAnchor.ArrowAnchor);
						else if ( innerPoints[i].Y == joinPoints[1].Y )
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { innerPoints[i], joinPoints[1] },
								LineAnchor.None, LineAnchor.ArrowAnchor);
						else if ( innerPoints[i].Y > joinPoints[2].Y )
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { innerPoints[i], new Point(joinPoints[2].X, innerPoints[i].Y), joinPoints[2] },
								LineAnchor.None, LineAnchor.ArrowAnchor);
						else
							DrawConnectors(e.Graphics,
								ConnectorPen,
								new Point[] { innerPoints[i], 
                                new Point(joinPoints[1].X-(int)((joinPoints[1].X-innerPoints[i].X)/1.5), innerPoints[i].Y), 
                                new Point(joinPoints[1].X-(int)((joinPoints[1].X-innerPoints[i].X)/1.5), joinPoints[1].Y), 
                                joinPoints[1] },
								LineAnchor.None, LineAnchor.ArrowAnchor);
					}
				}

				// rules
				foreach ( ActivityDesigner designer in ContainedDesigners ) {
					if ( designer is ConditionalBranchDesigner ) {
						string displayText = designer.Text;
						//if ( designer.Activity.GetValue(ConditionalBranchActivity.RuleProperty) != null ) {
						//    displayText = designer.Activity.Name; /* Name (RES) oder Description (IF Rule = RES) */
						//}
						StringFormat format = new StringFormat();
						format.FormatFlags = StringFormatFlags.NoWrap;
						format.Trimming = StringTrimming.EllipsisCharacter;
						e.Graphics.DrawString(displayText, e.DesignerTheme.Font,
											  e.DesignerTheme.ForegroundBrush,
												 new RectangleF(
													 new PointF(Bounds.X + (width / 2) + 12, WorkflowHelpers.GetCenter(designer.Bounds).Y - 24),
													 new SizeF(95, 19)), format);

					} else if ( designer is EventDrivenBranchDesigner ) {
						//if ( ( (CompositeActivity)designer.Activity ).Activities.Count > 0 ) {
						//    IncomingEvent inEvent = ( (CompositeActivity)designer.Activity ).Activities[0] as IncomingEvent;
						//    if ( inEvent == null ) continue;
						//    if ( inEvent.EventType == EventType.None ) continue;

						//    if ( !string.IsNullOrEmpty(inEvent.Text) ) branchText = inEvent.Text;
						//    else if ( !string.IsNullOrEmpty(inEvent.EventName) ) branchText = inEvent.EventName;
						//    else continue;

						//    e.Graphics.DrawString(branchText, /* Name (RES) oder Description (IF Rule = RES) */
						//        e.DesignerTheme.Font,
						//        e.DesignerTheme.ForegroundBrush,
						//        new Point(Bounds.X + width / 2 + 12, WorkflowHelpers.GetCenter(designer.Bounds).Y - 29));
						//}
					}
				}
				#endregion
			} else {
				using ( Pen borderPen = new Pen(Color.SlateGray) ) {
					borderPen.DashStyle = DashStyle.Dash;
					ActivityDesignerPaint.DrawRoundedRectangle(e.Graphics, borderPen, Bounds, 5);
				}
				Rectangle bounds = Bounds;
				bounds.Inflate(-10, 0);
				bounds.Offset(10, 0);
				ActivityDesignerPaint.DrawText(e.Graphics, e.DesignerTheme.Font, Activity.QualifiedName,
					bounds, StringAlignment.Center, TextQuality.Aliased, e.DesignerTheme.ForegroundBrush);
				#region Draw when collapsed
				//bounds = new Rectangle(Bounds.X, Bounds.Y + (Bounds.Height / 2) - (height / 2), width, height);

				//// draw start diamond
				//if (e.Graphics.IsVisible(bounds))
				//    PaintSplit(e);
				//else
				//    bounds.Inflate(SplitInflate, SplitInflate);

				//// change position to end
				//bounds.Inflate(JoinInflate, JoinInflate);

				//bounds.X += Bounds.Width - width;

				//// draw end diamond
				//if (e.Graphics.IsVisible(bounds))
				//    PaintJoin(e);

				//DrawConnectors(e.Graphics,
				//    e.DesignerTheme.ForegroundPen,
				//    new Point[] { 
				//        new Point(Bounds.Left + width, Bounds.Y + Bounds.Height / 2), 
				//        new Point(Bounds.Right - width, Bounds.Y + Bounds.Height / 2)
				//    },
				//    LineAnchor.None, LineAnchor.ArrowAnchor);

				//_collapsedEllipsis = ExpandButtonRectangle;
				//_collapsedEllipsis.Inflate(10, 10);
				//e.Graphics.FillRectangle(e.AmbientTheme.BackgroundBrush, _collapsedEllipsis);

				////e.Graphics.DrawString(".  .  .", _bigFont,
				////    e.DesignerTheme.ForegroundBrush, _collapsedEllipsis);
				#endregion
			}

			ActivityDesignerPaint.DrawExpandButton(e.Graphics, ExpandButtonRectangle, Expanded, (CompositeDesignerTheme)e.DesignerTheme);
		}

		private Rectangle GetJoinRectangle()
		{
			Rectangle rc = new Rectangle();
			rc.Location = new Point(Bounds.Right - joinSize - 30, Bounds.Top);
			rc.Size = new Size(joinSize + 30, Bounds.Height);
			return rc;
		}

		private Rectangle GetSplitRectangle()
		{
			Rectangle rc = new Rectangle();
			rc.Location = this.Location;
			rc.Size = new Size(width + 30, Bounds.Height);
			return rc;
		}

		#region Paint Methods
		protected virtual void PaintSplit(ActivityDesignerPaintEventArgs e)
		{
			GraphicsPath path = new GraphicsPath();
			path.AddPolygon(new Point[]{ 
					new Point(bounds.X,bounds.Y+height/2),
					new Point(bounds.X+width/2,bounds.Y),
					new Point(bounds.X+width,bounds.Y+height/2),
					new Point(bounds.X+width/2,bounds.Y+height)});
			e.Graphics.DrawPath(outerSymbolPen,path);
			e.Graphics.FillPath(BackgroundBrush, path);

		}

		protected virtual void PaintJoin(ActivityDesignerPaintEventArgs e)
		{
			bounds.Size = new Size(joinSize, joinSize);
			bounds.Location = new Point(Bounds.Right - joinSize, WorkflowHelpers.GetCenter(Bounds).Y - joinSize / 2);
			e.Graphics.FillEllipse(JoinBrush, bounds);
				//e.Graphics.DrawPolygon(outerSymbolPen, new Point[]{ 
				//    new Point(bounds.X,bounds.Y+height/2),
				//    new Point(bounds.X+width/2,bounds.Y),
				//    new Point(bounds.X+width,bounds.Y+height/2),
				//    new Point(bounds.X+width/2,bounds.Y+height)});

		}
		#endregion

		#region GetConnectionPoints
		protected virtual ReadOnlyCollection<Point> GetSplitConnections()
		{
			List<Point> list = new List<Point>(3);

			list.Add(new Point(Bounds.Left + ( width / 2 ), Bounds.Y + ( Bounds.Height / 2 ) - ( height / 2 )));
			if ( this == this.ActiveView.AssociatedDesigner ) {
				list.Add(new Point(Bounds.Left + width, Bounds.Y + ( Bounds.Height / 2 )));
			} else {
				list.Add(new Point(Bounds.Left, Bounds.Y + ( Bounds.Height / 2 )));
			}
			list.Add(new Point(Bounds.Left + ( width / 2 ), Bounds.Y + ( Bounds.Height / 2 ) + ( height / 2 )));

			ReadOnlyCollection<Point> roc = new ReadOnlyCollection<Point>(list);
			return roc;
		}

		protected virtual ReadOnlyCollection<Point> GetJoinConnections()
		{
			List<Point> list = new List<Point>(3);

			list.Add(new Point(Bounds.Right - ( joinSize / 2 ), Bounds.Y + ( Bounds.Height / 2 ) - ( joinSize / 2 )));
			if ( this == this.ActiveView.AssociatedDesigner ) {
				list.Add(new Point(Bounds.Right - joinSize, Bounds.Y + ( Bounds.Height / 2 )));
			} else {
				list.Add(new Point(Bounds.Right, Bounds.Y + ( Bounds.Height / 2 )));
			}
			list.Add(new Point(Bounds.Right - ( joinSize / 2 ), Bounds.Y + ( Bounds.Height / 2 ) + ( joinSize / 2 )));

			ReadOnlyCollection<Point> roc = new ReadOnlyCollection<Point>(list);
			return roc;
		}

		protected override ReadOnlyCollection<Point> GetInnerConnections(DesignerEdges edges)
		{
			List<Point> list = new List<Point>();

			if ( ( edges & DesignerEdges.Top ) == DesignerEdges.Top ||
				( edges & DesignerEdges.Bottom ) == DesignerEdges.Bottom ) {
				list.AddRange(base.GetInnerConnections(edges));
			}

			if ( ( edges & DesignerEdges.All ) == DesignerEdges.All )
				list.AddRange(GetSplitConnections());

			if ( ( edges & DesignerEdges.Left ) == DesignerEdges.Left ||
				( edges & DesignerEdges.Right ) == DesignerEdges.Right ) {
				foreach ( ActivityDesigner designer in ContainedDesigners ) {
					if ( ( edges & DesignerEdges.Left ) == DesignerEdges.Left )
						list.Add(new Point(designer.Bounds.Left, designer.Bounds.Y + designer.Bounds.Height / 2));
					if ( ( edges & DesignerEdges.Right ) == DesignerEdges.Right )
						list.Add(new Point(designer.Bounds.Right, designer.Bounds.Y + designer.Bounds.Height / 2));
				}
			}

			if ( ( edges & DesignerEdges.All ) == DesignerEdges.All )
				list.AddRange(GetJoinConnections());

			ReadOnlyCollection<Point> roc = new ReadOnlyCollection<Point>(list);
			return roc;
		}
		#endregion

		public override ReadOnlyCollection<DesignerView> Views
		{
			get
			{
				if ( _views == null ) {
					_views = new List<DesignerView>();
					_views.Add(new HorizontalView(1,
						string.Format("View {0}", this.Activity.GetType().Name),
						Resources.complex,
						this));
					_views.Add(new HorizontalView(2,
						"View Cancellation Handler",
						Resources.complex,
						this,
						typeof(HorizontalCancellationHandlerActivity)));
					_views.Add(new HorizontalView(3,
						"View Compensation Handler",
						Resources.complex,
						this,
						typeof(HorizontalCompensationHandlerActivity)));
					_views.Add(new HorizontalView(3,
						"View Fault Handler",
						Resources.complex,
						this,
						typeof(HorizontalFaultHandlersActivity)));
				}
				return _views.AsReadOnly();
			}
		}

		protected override void Initialize(Activity activity)
		{
			base.Initialize(activity);

			PerformLayout();
		}

		protected override void OnLayoutPosition(ActivityDesignerLayoutEventArgs e)
		{
			base.OnLayoutPosition(e);
			if ( this.ActiveView.AssociatedDesigner == this ) {
				if ( this.Activity.QualifiedName != this.Activity.GetType().Name ) {
					if ( ContainedDesigners.Count == 0 ) {
						_branchList.Clear();
						AddBranches(2);
						ReadOnlyCollection<Activity> roc = new ReadOnlyCollection<Activity>(_branchList);
						InsertActivities(HitTest(Location), roc);
					} else if ( ContainedDesigners.Count == 1 ) {
						_branchList.Clear();
						AddBranches(1);
						ReadOnlyCollection<Activity> roc = new ReadOnlyCollection<Activity>(_branchList);
						InsertActivities(HitTest(Location), roc);
					}
				}
				int verticalDistance = 10;
				foreach ( ActivityDesigner branch in ContainedDesigners ) {
					branch.Location = new Point(Location.X + 50, Location.Y + verticalDistance);
					verticalDistance += branch.Size.Height + 20;
				}
			} else {
				if ( ContainedDesigners.Count > 0 ) {
					Point center = WorkflowHelpers.GetCenter(Bounds);
					ContainedDesigners[0].Location = new Point(Bounds.Left + 50, center.Y - ContainedDesigners[0].Size.Height / 2);
				}
			}
		}

		protected override Size OnLayoutSize(ActivityDesignerLayoutEventArgs e)
		{
			if ( Expanded ) {
				Size size = base.OnLayoutSize(e);
				if ( this.Activity.QualifiedName != this.Activity.GetType().Name ) {
					size.Width += ( width * 2 ) - 20;
					if ( Expanded )
						size.Height += 15;

					if ( ParentDesigner != null ) {
						// assign width of the longest branch to all branches
						int w = 0;
						int h = 10; // verticalDistance(start value) = 10 in OnLayoutPosition
						foreach ( ActivityDesigner designer in ContainedDesigners ) {
							if ( designer.Size.Width > w )
								w = designer.Size.Width;
							h += designer.Size.Height + 20;
						}
						size.Height = h;

						foreach ( ActivityDesigner designer in ContainedDesigners ) {
							designer.Size = new Size(w, designer.Size.Height);
						}
					}
				}
				return size;
			} else {
				return MinimumSize;
			}
		}

		protected override Rectangle[] GetConnectors()
		{
			return new Rectangle[] { };
			//return base.GetConnectors();
		}

		protected override Rectangle[] GetDropTargets(Point dropPoint)
		{
			return new Rectangle[] { };
			//return base.GetDropTargets(dropPoint);
		}

		protected override void OnMouseCaptureChanged()
		{
			base.OnMouseCaptureChanged();
		}

		protected override ActivityDesignerVerbCollection Verbs
		{
			get
			{
				try {
					if ( this.verbs == null )
						CreateActivityVerbs();

					if ( this.verbs != null )
						base.Verbs.AddRange(this.verbs);

				} catch ( Exception ex ) {
					MessageBox.Show(string.Format("{0} has encountered an error at {1}:{2}{2}{3}", ex.Source, ex.TargetSite, Environment.NewLine, ex.Message),
						"Unhandled Exception");
				}

				return base.Verbs;
			}
		}

		private void CreateActivityVerbs()
		{
			try {
				this.verbs = new ActivityDesignerVerbCollection();
				this.verbs.Clear();

				this.verbs.Add(new ActivityDesignerVerb(this, DesignerVerbGroup.Actions, "Add Branch",
					new EventHandler(OnAddBranch)));
			} catch ( Exception ex ) {
				MessageBox.Show(ex.Source + " has encountered an error at " + ex.TargetSite + ":" + Environment.NewLine + Environment.NewLine +
					ex.Message, "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void OnAddBranch(object sender, EventArgs e)
		{
			try {
				_branchList.Clear();
				AddBranches(1);
				ReadOnlyCollection<Activity> roc = new ReadOnlyCollection<Activity>(_branchList);
				InsertActivities(HitTest(Location), roc);
			} catch ( Exception ex ) {
				MessageBox.Show(ex.Source + " has encountered an error at " + ex.TargetSite + ":" + Environment.NewLine + Environment.NewLine +
					ex.Message, "Unhandled Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		protected override void Dispose(bool disposing)
		{
			outerSymbolPen.Dispose();
			_bigFont.Dispose();

			base.Dispose(disposing);
		}

		///// <summary>
		///// Pixels to inflate the split symbol
		///// </summary>
		//protected virtual int SplitInflate
		//{
		//    get { return -10; }
		//}

		///// <summary>
		///// Pixels to inflate the join symbol
		///// </summary>
		//protected virtual int JoinInflate
		//{
		//    get { return 10; }
		//}

		protected override Rectangle ExpandButtonRectangle
		{
			get
			{
				if ( Expanded )
					_ExpandButtonRectangle.Location =
						new Point(Bounds.Left + 6,
							WorkflowHelpers.GetCenter(Bounds).Y - 60);
				else
					_ExpandButtonRectangle.Location =
						new Point(Bounds.Left + 7,
							WorkflowHelpers.GetCenter(Bounds).Y - _ExpandButtonRectangle.Height / 2);
				return _ExpandButtonRectangle;
			}
		}

		private void set_ExpandButtonRectangle()
		{
			_ExpandButtonRectangle = new Rectangle(
				new Point(Bounds.Left + Bounds.Width / 2,
				Bounds.Top + 15),
				base.ExpandButtonRectangle.Size);
		}

		protected override Rectangle ImageRectangle
		{
			get { return new Rectangle(); }
		}

		protected override Rectangle TextRectangle
		{
			get { return new Rectangle(); }
		}

		protected override Rectangle SmartTagRectangle
		{
			get { return new Rectangle(); }
		}

		protected virtual BranchType BranchType
		{
			get { return BranchType.Conditional; }
		}

		protected Font TextFont
		{
			get { return _mediumFont; }
		}

		protected override ActivityDesignerGlyphCollection Glyphs
		{
			get
			{
				ActivityDesignerGlyphCollection myGlyphs = base.Glyphs;
				if ( ( (DecisionActivity)this.Activity ).Activities.Find(FindCancellationHandler) != null ) {
					myGlyphs.Add(new CompensationGlyph(new EventHandler(handleGlyphClick)));
				}
				if ( ( (DecisionActivity)this.Activity ).Activities.Find(FindFaultHandler) != null ) {
					myGlyphs.Add(new ExceptionGlyph(new EventHandler(handleGlyphClick)));
				}
				return myGlyphs;
				//return base.Glyphs;
			}
		}

		// sender is DesignerGlpyh
		// e is EventArgs.Empty
		private void handleGlyphClick(object sender, EventArgs e)
		{
			if ( sender is CompensationGlyph ) {
				if ( !( this.ActiveView.AssociatedDesigner is HorizontalCancellationHandlerDesigner ) ) {
					this.ActiveView = _views[1];
				} else {
					this.ActiveView = _views[0];
				}
			} else if ( sender is ExceptionGlyph ) {
				if ( !( this.ActiveView.AssociatedDesigner is HorizontalFaultHandlersDesigner ) ) {
					this.ActiveView = _views[3];
				} else {
					this.ActiveView = _views[0];
				}
			}
		}

		private bool FindCancellationHandler(Activity activity)
		{
			if ( activity is HorizontalCancellationHandlerActivity ) return true;
			else return false;
		}

		private bool FindFaultHandler(Activity activity)
		{
			if ( activity is HorizontalFaultHandlersActivity ) return true;
			else return false;
		}

		protected virtual void AddBranches(int count)
		{
			switch ( BranchType ) {
				case BranchType.Normal:
					for (int i = 0; i < count; i++) {
						_branchList.Add(new HorizontalBranchActivity());
					}
					break;
				case BranchType.Conditional:
					for ( int i = 0; i < count; i++ ) {
						_branchList.Add(new ConditionalBranchActivity());
					}
					break;
				case BranchType.Event:
					for ( int i = 0; i < count; i++ ) {
						_branchList.Add(new EventDrivenBranch());
					}
					break;
			}

			PerformLayout();
		}

		public override bool CanInsertActivities(HitTestInfo insertLocation, ReadOnlyCollection<Activity> activitiesToInsert)
		{
			if ( activitiesToInsert.Count == 0 )
				return false;

			if ( activitiesToInsert[0] is HorizontalSequenceActivity )
				return true;
			else
				return false;
		}
	}

	public class DecisionActivityValidator : ActivityValidator
	{
		public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
		{
			return new ValidationErrorCollection();
		}
	}

	public enum BranchType
	{
		Normal = 0,
		Conditional = 1,
		Event = 2
	}

	public enum RunType
	{
		Analytic,
		RandomVariables,
		RandomDocuments
	}

}
